#if !USE_CONSOLE

#include "src/interface/output.h"

#include <QDebug>
#include <QString>
#include <QFileInfo>
#include <QFile>
#include <iostream>

#include "src/math/vector3d.h"

#include "src/scene/cuboidPrimitive.h"
#include "src/scene/spherePrimitive.h"
#include "src/scene/conePrimitive.h"
#include "src/scene/cylinderPrimitive.h"
#include "src/scene/combinedObject.h"
#include "src/scene/pointLight.h"
#include "src/scene/areaLight.h"
#include "src/scene/raytracing.h"
#include "src/scene/photonMapping.h"

#include "src/defines/primitive.h"
#include "src/defines/light.h"
#include "src/defines/antialiasingType.h"
#include "src/defines/filterType.h"

Output::Output(){
    file = NULL;
}

Output::~Output(){
}

void Output::parseObjects(QFile *_file, Scene *_s){
    file = _file;

    parseObjects(_s);
}

void Output::parseObjects(Scene *_s){
    file->open(QFile::WriteOnly);
    QTextStream stream(file);

    //i - informação
    //m - informaçõe sde photon mapping
    //o - objeto composto
    //p - primitiva
    //l - luz
        //AMBIENT_LIGHT - luz ambiente
        //POINT_LIGHT - luz pontual
        //AREA_LIGHT - luz em area
    //c - camera
    //s - antialiasing
        //REGULAR - regular
        //JITTERING - jittering
        //RANDOM - random
    //f - filtro
        //MEAN - media
        //GAUSSIAN - gaussiano
        //LAPLACIAN - laplaciano
        //WEIGHTED_AVERANGE - pedia ponderada
    //d - depth of field
    Color backgroundColor = _s->getBackgroundColor();
    Raytracing *raytracing = _s->getRaytracing();
    PhotonMapping *photonMapping = _s->getPhotonMapping();
    stream << "i " << raytracing->getDepth() << " " << backgroundColor.red << " " << backgroundColor.green << " " << backgroundColor.blue << endl;
    stream << "m " << photonMapping->getPhotonDepth() << " "
                   << photonMapping->getMaxPhotons() << " " << photonMapping->getMaxNearestPhotons() << " " << photonMapping->getMaxRadius() << " "
                   << photonMapping->getCausticMaxPhotons() << " " << photonMapping->getCausticMaxNearestPhotons() << " " << photonMapping->getCausticMaxRadius() << " "
                   << photonMapping->getFilter() << " " << photonMapping->getConeFilterConstant() << " " << photonMapping->getTestReflexion() << " " << photonMapping->getKeepFirstBounce()
                   << endl;



	for(unsigned int i = 0; i < _s->getObjectsSize(); i++){
	    Object *object = _s->getObject(i);
	    //cada linha representará um objeto
	    writeObject(&stream, object);
	}
	for(unsigned int i = 0; i < _s->getLightsSize(); i++){
	    Light *light = _s->getLight(i);
	    //cada linha representará um objeto
	    writeLight(&stream, light);
	}

    writeCamera(&stream, _s->getCamera());
    file->close();
}

void Output::writeObject(QTextStream *_stream, Object *_obj, int _parentId){

    int type = _obj->getType();
    int id = _obj->getId();
    Material m = _obj->getMaterial();
    Vector3D center = _obj->getCenter();
    Vector3D relativePos;// = _obj->getRelativePosition();
    Transformation trans = _obj->getTransformation();
    Matrix matrix = trans.getLocalToWorld();
    Matrix matrixI = trans.getWorldToLocal();

    if(_obj->isPrimitive()){
        (*_stream)<< "p " << id << " " << type  << " " << _parentId //p de primitiva
                  << " " << m.ambient.red << " " << m.ambient.green << " " << m.ambient.blue << " " << m.ambient.alpha
                  << " " << m.diffuse.red << " " << m.diffuse.green << " " << m.diffuse.blue << " " << m.diffuse.alpha
                  << " " << m.specular.red << " " << m.specular.green << " " << m.specular.blue << " " << m.specular.alpha
                  << " " << m.specularPower << " " << m.ka << " " << m.kd << " " << m.ks << " " << m.kt << " " << m.refractiveIndex
                  << " " << center.x << " " << center.y << " " << center.z
                  << " " << relativePos.x << " " << relativePos.y << " " << relativePos.z
                  << " " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3]
                  << " " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3]
                  << " " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3]
                  << " " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3]
                  << " " << matrixI[0][0] << " " << matrixI[0][1] << " " << matrixI[0][2] << " " << matrixI[0][3]
                  << " " << matrixI[1][0] << " " << matrixI[1][1] << " " << matrixI[1][2] << " " << matrixI[1][3]
                  << " " << matrixI[2][0] << " " << matrixI[2][1] << " " << matrixI[2][2] << " " << matrixI[2][3]
                  << " " << matrixI[3][0] << " " << matrixI[3][1] << " " << matrixI[3][2] << " " << matrixI[3][3]
                  << " ";
        switch(type){
            case CUBOID:{
                Vector3D min = ((CuboidPrimitive *)_obj)->getMin();
                Vector3D max = ((CuboidPrimitive *)_obj)->getMax();
                (*_stream) << min.x << " " << min.y << " " << min.z << " " << max.x << " " << max.y << " " << max.z << endl;
                break;
            }
            case SPHERE:{
                double radius = ((SpherePrimitive *)_obj)->getRadius();
                (*_stream) << radius << endl;
                break;
            }
            case CYLINDER:{
                double radius = ((CylinderPrimitive *)_obj)->getRadius();
                double height = ((CylinderPrimitive *)_obj)->getHeight();
                (*_stream) << radius << " " << height << endl;
                break;
            }
            case CONE:{
                double radius = ((ConePrimitive *)_obj)->getRadius();
                double height = ((ConePrimitive *)_obj)->getHeight();
                (*_stream) << radius << " " << height << endl;
                break;
            }
        }


        if(m.useTexture()) (*_stream)<< "t " << m.texture->textureImagePathName << " " << m.texture->repeatTimesU << " " << m.texture->repeatTimesV << " " << m.texture->mappingType << " " << m.texture->coloringType << endl;
        if(m.useBumpMapping()) (*_stream)<< "b " << m.bumpMapping->bumpMappingImagePathName << " " << m.bumpMapping->repeatTimesU << " " << m.bumpMapping->repeatTimesV << " " << m.bumpMapping->mappingType << " " << m.bumpMapping->bumpIntensity << " " << m.bumpMapping->loop<< endl;

    }
    else{
        (*_stream)<< "o " << id << " " << type  << " " << _parentId //o de objeto composto
                  << " " << m.ambient.red << " " << m.ambient.green << " " << m.ambient.blue << " " << m.ambient.alpha
                  << " " << m.diffuse.red << " " << m.diffuse.green << " " << m.diffuse.blue << " " << m.diffuse.alpha
                  << " " << m.specular.red << " " << m.specular.green << " " << m.specular.blue << " " << m.specular.alpha
                  << " " << m.specularPower << " " << m.ka << " " << m.kd << " " << m.ks << " " << m.kt << " " << m.refractiveIndex
                  << " " << center.x << " " << center.y << " " << center.z
                  << " " << relativePos.x << " " << relativePos.y << " " << relativePos.z
                  << " " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3]
                  << " " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3]
                  << " " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3]
                  << " " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3]
                  << " " << matrixI[0][0] << " " << matrixI[0][1] << " " << matrixI[0][2] << " " << matrixI[0][3]
                  << " " << matrixI[1][0] << " " << matrixI[1][1] << " " << matrixI[1][2] << " " << matrixI[1][3]
                  << " " << matrixI[2][0] << " " << matrixI[2][1] << " " << matrixI[2][2] << " " << matrixI[2][3]
                  << " " << matrixI[3][0] << " " << matrixI[3][1] << " " << matrixI[3][2] << " " << matrixI[3][3]
                  << endl;

        if(m.useTexture()) (*_stream)<< "t " << m.texture->textureImagePathName << " " << m.texture->repeatTimesU << " " << m.texture->repeatTimesV << " " << m.texture->mappingType << " " << m.texture->coloringType << endl;
        if(m.useBumpMapping()) (*_stream)<< "b " << m.bumpMapping->bumpMappingImagePathName << " " << m.bumpMapping->repeatTimesU << " " << m.bumpMapping->repeatTimesV << " " << m.bumpMapping->mappingType << " " << m.bumpMapping->bumpIntensity << " " << m.bumpMapping->loop << endl;

        for(unsigned int i = 0; i < ((CombinedObject *)_obj)->getObjectsSize(); i++){
            Object *obj = ((CombinedObject *)_obj)->getObject(i);
            writeObject(_stream, obj, id);
        }
    }
}

void Output::writeLight(QTextStream *_stream, Light *_light){
    //l - luz
        //AMBIENT_LIGHT - luz ambiente
        //POINT_LIGHT - luz pontual
        //AREA_LIGHT - luz em area
    switch(_light->getType())
    {
        case AMBIENT_LIGHT:
        {
            Color color = _light->getColor();
            (*_stream)<< "l " << _light->getType() << " " << color.red << " " << color.green << " " << color.blue << endl;
            break;
        }
        case POINT_LIGHT:
        {
            Color color = _light->getColor();
            Vector3D position = ((PointLight *)_light)->getPosition();
            (*_stream)<< "l " << _light->getType() << " " << color.red << " " << color.green << " " << color.blue << " "
                      << position.x << " " << position.y << " " << position.z << " " << _light->getEnergy() << endl;
            break;
        }
        case AREA_LIGHT:
        {
            Color color = _light->getColor();
            Vector3D position = ((AreaLight *)_light)->getPosition();
            Vector3D a = ((AreaLight *)_light)->getA();
            Vector3D b = ((AreaLight *)_light)->getB();
            (*_stream)<< "l " << _light->getType() << " " << color.red << " " << color.green << " " << color.blue << " "
                      << position.x << " " << position.y << " " << position.z << " "
                      << a.x << " " << a.y << " " << a.z << " "
                      << b.x << " " << b.y << " " << b.z << " " << _light->getEnergy() << endl;
            break;
        }
    }
}

void Output::writeCamera(QTextStream *_stream, Camera *_camera){
    Vector3D eye = _camera->getEye();
    Vector3D lookAt = _camera->getLookAt();
    Vector3D up = _camera->getUp();
    (*_stream) << "c " << eye.x << " " << eye.y << " " << eye.z << " "
               << lookAt.x << " " << lookAt.y << " " << lookAt.z << " "
               << up.x << " " << up.y << " " << up.z << " "
               << _camera->getM() << " " << _camera->getN() << " "
               << _camera->getImagePlane() << " "
               << _camera->getZoom() << endl;

    //s - antialiasing
        //REGULAR - regular
        //JITTERING - jittering
        //RANDOM - random
    bool b = false;
    if(_camera->getAntialiasingType() != NO_ANTIALIASING)
    {
        b = true;
        (*_stream) << "s " << _camera->getAntialiasingType() << " " << _camera->getMPerPixel() << " " << _camera->getNPerPixel()<< endl;
    }

    //f - filtro
        //MEAN - media
        //GAUSSIAN - gaussiano
        //LAPLACIAN - laplaciano
        //WEIGHTED_AVERANGE - pedia ponderada
    if(b){
        switch(_camera->getFilterType())
        {
            case MEAN:
            {
                (*_stream) <<"f " << _camera->getFilterType() << endl;
                break;
            }
            case GAUSSIAN:
            {
                (*_stream) <<"f " << _camera->getFilterType() << " " << _camera->getFilterGaussianSigma() << endl;
                break;
            }
            case LAPLACIAN:
            {
                (*_stream) <<"f " << _camera->getFilterType() << " " << _camera->getFilterLaplacianNeighborhood() << " " << _camera->getFilterLaplacianNegative()<< endl;
                break;
            }
            case WEIGHTED_AVERANGE:
            {
                (*_stream) <<"f " << _camera->getFilterType() << endl;
                break;
            }

        }
    }

    if(_camera->getDepthOfField())
    {
        (*_stream) << "d " << _camera->getFocalDistance() << " " << _camera->getRadius() << endl;
    }
}


bool Output::isFileNull(){
    if(file) return false;
    return true;
}

void Output::setFile(QFile *_file){
    file = _file;
}
#endif //!USE_CONSOLE
